package main

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io/ioutil"
	"os"
)

func main() {
	fmt.Println("使用gzip进行流压缩解压的示例，在网络传输中经常需要用到。")

	// STEP 1: 从文件中读取数据，模拟这是在网络中要发出去的数据。
	inputRawFile, err := os.Open("zh_CN.json")
	if err != nil {
		fmt.Println("Error opening file:", err.Error())
		return
	}

	fileData := make([]byte, 0)
	dataSlice := make([]byte, 1024)
	totalCnd := 0

	for {
		nRead, err_i := inputRawFile.Read(dataSlice)
		if err_i != nil {
			println("Error: ", err_i.Error())
			break
		}
		//fmt.Println("read cnt:", nRead)
		//
		//Tips: 注意slice合并的操作！
		//append的从第二个参数是不定长参数，例如append(sliceA, elem1, elem2)
		//下面dataSlice[:nRead]...的意思是从dataSlice中取出nRead个字节，并将它展开（或者叫解构）。
		//dataSlice的长度在上边定义的时候预设了1024个字节，所以append不要直接使用“dataSlice...”，
		//不然会将整个1024字节全部添加到fileData中，实际上最后一次读取的长度并不足1024个字节。
		//
		fileData = append(fileData, dataSlice[:nRead]...)
		totalCnd += nRead

	}

	fmt.Println("文件读取长度:", len(fileData), totalCnd)

	defer inputRawFile.Close()

	// Step 2: 压缩数据流，输入数据流现在为一个slice，输出数据流为bytes.Buffer类型。
	// Tips:
	// gzip.NewWriter使用一个*io.Write的参数，不接受slice，所以下面这两行代码是错误的。
	//dataCompressed := make([]byte, 0)
	//var newWriter *gzip.Writer = gzip.NewWriter(dataCompressed)
	var aCompressedBuffer bytes.Buffer
	var newWrite *gzip.Writer = gzip.NewWriter(&aCompressedBuffer)
	newWrite.Write(fileData)
	newWrite.Close()
	fmt.Println("压缩后的长度:", aCompressedBuffer.Len())

	// Step 3: 解压数据流，现在输入数据流是bytes.Buffer类型，输出数据流是一个slice。
	var newReader *gzip.Reader
	var errR error
	newReader, errR = gzip.NewReader(&aCompressedBuffer)
	if errR != nil {
		fmt.Println("Error setup gzip reader:", errR.Error())
	} else {
		// Tips:
		// 这里不能使用newReader.Read方法，得使用ioutil.ReadAll。
		uncompressedBytes, err := ioutil.ReadAll(newReader)
		if err != nil {
			fmt.Println(err.Error())
		} else {
			fmt.Println("解压后的长度:", len(uncompressedBytes))
		}
		newReader.Close()
	}

}
